﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OOLib
{
   /// <summary>
   /// Is the environment for components which can instantiate within frames 
   /// </summary>
   /// <remarks>
   /// A desktop environment contains tasks with one or more frames in which components can be loaded. 
   /// The term "task" or naming a frame as a "task frame" is not in any way related to any additional 
   /// implemented interfaces, it's just because these frames use task windows.
   /// </remarks>
   public class Desktop : ComObjectWrapper, IComponentLoader
   {
      #region Constructors

      /// <summary>
      /// Constructor
      /// </summary>
      /// <remarks>
      /// After using this constructor, the ComObj must be set manually!
      /// </remarks>
      public Desktop() :
         base()
      { }

      /// <summary>
      /// Constructor
      /// </summary>
      /// <param name="comObject">COM object</param>
      public Desktop(object comObject) :
         base(comObject)
      { }

      #endregion

      #region XDesktop
      
      /// <summary>
      /// Tries to terminate the desktop. 
      /// </summary>
      /// <returns>
      /// true if all listener agree with this request 
      /// false otherwise 
      /// </returns>
      /// <remarks>
      /// First, every terminate listener is called by his XTerminateListener::queryTermination() method. 
      /// Throwing of a TerminationVetoException can break the termination process and the listener how has 
      /// done that will be the new "controller" of the desktop lifetime. He should try to terminate it by 
      /// himself after his own processes will be finished. If nobody disagree with the termination request, 
      /// every listener will be called by his XTerminateListener::notifyTermination() method. 
      /// </remarks>
      public bool Terminate()
      {
         return (bool)InvokeMethod("terminate");
      }

      /// <summary>
      /// Provides read access to collection of all currently loaded components inside the frame tree.
      /// </summary>
      /// <returns>Returns the collection of all components.</returns>
      /// <remarks>
      /// The component is, by definition, the model of the control which is loaded into a frame, or if no model exists, 
      /// into the control itself. The service Components which is available from this method is a collection of all 
      /// components of the desktop which are open within a frame of the desktop.
      /// !!! Not tested !!!
      /// </remarks>
      public EnumerationAccess GetComponents()
      {
         CheckDisposed();
         return GetObjectWrapper<EnumerationAccess>(InvokeMethod("getComponents"));
      }

      /// <summary>
      /// Gets read access to the component inside the tree which has the UI focus .
      /// </summary>
      /// <remarks>
      /// Normally, the component is the model part of the active component. If no model exists it is the active controller (view) itself. 
      /// !!! not tested !!!
      /// </remarks>
      public Component CurrentComponent
      {
         get
         {
            CheckDisposed();
            return GetObjectWrapper<Component>(InvokeMethod("getCurrentComponent"));
         }
      }

      /// <summary>
      /// Gets read access to the frame wich contains the current component.
      /// </summary>
      /// <remarks>
      /// !!! Not tested !!!
      /// </remarks>
      public Frame CurrentFrame
      {
         get
         {
            CheckDisposed();
            return GetObjectWrapper<Frame>(InvokeMethod("getCurrentFrame"));
         }
      }

      //todo support listeners

      #endregion

      #region IComponentLoader

      /// <summary>
      /// Loads a component specified by an URL into the specified new or existing frame.
      /// </summary>
      /// <param name="url">
      /// Specifies the URL of the document to load.
      /// To create new documents, use "private:factory/scalc", "private:factory/swriter", 
      /// etc. Other special protocols (e.g. "slot:", ".uno") are not allowed and raise an ::com::sun::star::lang::IllegalArgumentException. 
      /// </param>
      /// <param name="targetFrameName">
      /// Specifies the name of the frame to view the document in.
      /// If a frame with the specified name already exists, it is used, otherwise it is created. 
      /// There exist some special targets which never can be used as real frame names: 
      /// "_blank" always creates a new frame 
      /// "_default" special UI functionality (e.g. detecting of already loaded documents, using of empty frames of creating of new top frames as fallback) 
      /// "_self", ""(!) means frame himself 
      /// "_parent" address direct parent of frame 
      /// "_top" indicates top frame of current path in tree 
      /// "_beamer" means special sub frame 
      /// </param>
      /// <param name="searchFlags">
      /// Use the values of FrameSearchFlag to specify how to find the specified TargetFrameName.
      /// Note: These flags are optional ones and will be used for non special target names only.
      /// </param>
      /// <param name="hidden">true if the Window in which the document is opend should be hidden, false otherwiese.</param>
      /// <returns>Returns the raw Com object</returns>
      public object LoadComponentFromURLRaw(string url, string targetFrameName, int searchFlags, bool hidden)
      {
         return LoadComponentFromURLRaw(url, targetFrameName, searchFlags, new[] { ServiceManager.Instance.CoreReflection.CreateProperty("Hidden", hidden) });
      }

      /// <summary>
      /// Loads a component specified by an URL into the specified new or existing frame.
      /// </summary>
      /// <param name="url">
      /// Specifies the URL of the document to load.
      /// To create new documents, use "private:factory/scalc", "private:factory/swriter", 
      /// etc. Other special protocols (e.g. "slot:", ".uno") are not allowed and raise an ::com::sun::star::lang::IllegalArgumentException. 
      /// </param>
      /// <param name="targetFrameName">
      /// Specifies the name of the frame to view the document in.
      /// If a frame with the specified name already exists, it is used, otherwise it is created. 
      /// There exist some special targets which never can be used as real frame names: 
      /// "_blank" always creates a new frame 
      /// "_default" special UI functionality (e.g. detecting of already loaded documents, using of empty frames of creating of new top frames as fallback) 
      /// "_self", ""(!) means frame himself 
      /// "_parent" address direct parent of frame 
      /// "_top" indicates top frame of current path in tree 
      /// "_beamer" means special sub frame 
      /// </param>
      /// <param name="searchFlags">
      /// Use the values of FrameSearchFlag to specify how to find the specified TargetFrameName.
      /// Note: These flags are optional ones and will be used for non special target names only.
      /// </param>
      /// <param name="arguments">
      /// these arguments specify component or filter specific behavior.
      /// For example, "ReadOnly" with a boolean value specifies whether the document is opened read-only. 
      /// "FilterName" specifies the component type to create and the filter to use, for example: 
      /// "Text - CSV". For more information see ::com::sun::star::document::MediaDescriptor.
      /// </param>
      /// <returns>Returns the raw Com object</returns>
      public object LoadComponentFromURLRaw(string url, string targetFrameName, int searchFlags, object[] arguments)
      {
         CheckDisposed();
         return InvokeMethod("loadComponentFromURL", url, targetFrameName, searchFlags, arguments);
      }

      /// <summary>
      /// Loads a component specified by an URL into the specified new or existing frame.
      /// </summary>
      /// <param name="url">
      /// Specifies the URL of the document to load.
      /// To create new documents, use "private:factory/scalc", "private:factory/swriter", 
      /// etc. Other special protocols (e.g. "slot:", ".uno") are not allowed and raise an ::com::sun::star::lang::IllegalArgumentException. 
      /// </param>
      /// <param name="targetFrameName">
      /// Specifies the name of the frame to view the document in.
      /// If a frame with the specified name already exists, it is used, otherwise it is created. 
      /// There exist some special targets which never can be used as real frame names: 
      /// "_blank" always creates a new frame 
      /// "_default" special UI functionality (e.g. detecting of already loaded documents, using of empty frames of creating of new top frames as fallback) 
      /// "_self", ""(!) means frame himself 
      /// "_parent" address direct parent of frame 
      /// "_top" indicates top frame of current path in tree 
      /// "_beamer" means special sub frame 
      /// </param>
      /// <param name="searchFlags">
      /// Use the values of FrameSearchFlag to specify how to find the specified TargetFrameName.
      /// Note: These flags are optional ones and will be used for non special target names only.
      /// </param>
      /// <param name="hidden">true if the Window in which the document is opend should be hidden, false otherwiese.</param>
      /// <returns>
      /// Returns a ::com::sun::star::lang::XComponent for successfully loaded documents or NULL if it failed .
      /// This interface is a generic one and can be used to start further requests on loaded document or control the 
      /// lifetime of it (means dispose() it after using). The real document service behind this interface can be one of follow three ones: 
      /// ::com::sun::star::awt::XWindow for simple components Should be used for viewable components only. 
      /// It is not allowed to dispose it after use directly, because the frame containing the component is its owner. 
      /// Because the frame object is not accessible through the interface too, only an interacting user can do this by closing the frames' window. 
      /// XController for richer components Should be used for real editable components which doesn't need a model. 
      /// It is not allowed to dispose it after use directly, because the frame containing the component is its owner. 
      /// Here the object can be disposed by disposing the frame, that the XController::getFrame() method of the controller returns. 
      /// But for visible components the controller should be asked for permission by calling XController::suspend() before. 
      /// XModel for full featured components
      /// A model that in general can be shared between several view/controller pairs, does not have an explicit owner. 
      /// Every view and also the component that loaded the document may consider itself as an owner. Simply calling XComponent::dispose 
      /// on this model may cause problems, if some members of the "owner community" are currently busy working on the model. 
      /// These problems are handled by explicit closing negotiations through the interface ::com::sun::star::util::XCloseable. 
      /// Direct dispose of the model is allowed only, if this special interface doesn't exist.
      /// </returns>
      public T LoadComponentFromURL<T>(string url, string targetFrameName = "_blank", FrameSearchFlag searchFlags = FrameSearchFlag.AUTO, bool hidden = false) where T : Component, new()
      {
         return new T()
            {
               ComObj = LoadComponentFromURLRaw(url, targetFrameName, (int)searchFlags, hidden)
            };
      }

      /// <summary>
      /// Loads a component specified by an URL into the specified new or existing frame.
      /// </summary>
      /// <param name="url">
      /// Specifies the URL of the document to load.
      /// To create new documents, use "private:factory/scalc", "private:factory/swriter", 
      /// etc. Other special protocols (e.g. "slot:", ".uno") are not allowed and raise an ::com::sun::star::lang::IllegalArgumentException. 
      /// </param>
      /// <param name="targetFrameName">
      /// Specifies the name of the frame to view the document in.
      /// If a frame with the specified name already exists, it is used, otherwise it is created. 
      /// There exist some special targets which never can be used as real frame names: 
      /// "_blank" always creates a new frame 
      /// "_default" special UI functionality (e.g. detecting of already loaded documents, using of empty frames of creating of new top frames as fallback) 
      /// "_self", ""(!) means frame himself 
      /// "_parent" address direct parent of frame 
      /// "_top" indicates top frame of current path in tree 
      /// "_beamer" means special sub frame 
      /// </param>
      /// <param name="searchFlags">
      /// Use the values of FrameSearchFlag to specify how to find the specified TargetFrameName.
      /// Note: These flags are optional ones and will be used for non special target names only.
      /// </param>
      /// <param name="arguments">
      /// these arguments specify component or filter specific behavior.
      /// For example, "ReadOnly" with a boolean value specifies whether the document is opened read-only. 
      /// "FilterName" specifies the component type to create and the filter to use, for example: 
      /// "Text - CSV". For more information see ::com::sun::star::document::MediaDescriptor.
      /// </param>
      /// <returns>
      /// Returns a ::com::sun::star::lang::XComponent for successfully loaded documents or NULL if it failed .
      /// This interface is a generic one and can be used to start further requests on loaded document or control the 
      /// lifetime of it (means dispose() it after using). The real document service behind this interface can be one of follow three ones: 
      /// ::com::sun::star::awt::XWindow for simple components Should be used for viewable components only. 
      /// It is not allowed to dispose it after use directly, because the frame containing the component is its owner. 
      /// Because the frame object is not accessible through the interface too, only an interacting user can do this by closing the frames' window. 
      /// XController for richer components Should be used for real editable components which doesn't need a model. 
      /// It is not allowed to dispose it after use directly, because the frame containing the component is its owner. 
      /// Here the object can be disposed by disposing the frame, that the XController::getFrame() method of the controller returns. 
      /// But for visible components the controller should be asked for permission by calling XController::suspend() before. 
      /// XModel for full featured components
      /// A model that in general can be shared between several view/controller pairs, does not have an explicit owner. 
      /// Every view and also the component that loaded the document may consider itself as an owner. Simply calling XComponent::dispose 
      /// on this model may cause problems, if some members of the "owner community" are currently busy working on the model. 
      /// These problems are handled by explicit closing negotiations through the interface ::com::sun::star::util::XCloseable. 
      /// Direct dispose of the model is allowed only, if this special interface doesn't exist.
      /// </returns>
      public T LoadComponentFromURLWithArgs<T>(string url, string targetFrameName = "_blank", FrameSearchFlag searchFlags = FrameSearchFlag.AUTO, object[] arguments = null) where T : Component, new()
      {
         if (arguments == null)
         {
            arguments = new object[0];
         }
         return new T()
         {
            ComObj = LoadComponentFromURLRaw(url, targetFrameName, (int)searchFlags, arguments)
         };
      }

      /// <summary>
      /// Loads a component specified by an URL into the specified new or existing frame.
      /// </summary>
      /// <param name="fileName">Specifies the file name of the document to load.</param>
      /// <param name="targetFrameName">
      /// Specifies the name of the frame to view the document in.
      /// If a frame with the specified name already exists, it is used, otherwise it is created. 
      /// There exist some special targets which never can be used as real frame names: 
      /// "_blank" always creates a new frame 
      /// "_default" special UI functionality (e.g. detecting of already loaded documents, using of empty frames of creating of new top frames as fallback) 
      /// "_self", ""(!) means frame himself 
      /// "_parent" address direct parent of frame 
      /// "_top" indicates top frame of current path in tree 
      /// "_beamer" means special sub frame 
      /// </param>
      /// <param name="searchFlags">
      /// Use the values of FrameSearchFlag to specify how to find the specified TargetFrameName.
      /// Note: These flags are optional ones and will be used for non special target names only.
      /// </param>
      /// <param name="hidden">true if the Window in which the document is opend should be hidden, false otherwiese.</param>
      /// <returns>
      /// Returns a ::com::sun::star::lang::XComponent for successfully loaded documents or NULL if it failed .
      /// This interface is a generic one and can be used to start further requests on loaded document or control the 
      /// lifetime of it (means dispose() it after using). The real document service behind this interface can be one of follow three ones: 
      /// ::com::sun::star::awt::XWindow for simple components Should be used for viewable components only. 
      /// It is not allowed to dispose it after use directly, because the frame containing the component is its owner. 
      /// Because the frame object is not accessible through the interface too, only an interacting user can do this by closing the frames' window. 
      /// XController for richer components Should be used for real editable components which doesn't need a model. 
      /// It is not allowed to dispose it after use directly, because the frame containing the component is its owner. 
      /// Here the object can be disposed by disposing the frame, that the XController::getFrame() method of the controller returns. 
      /// But for visible components the controller should be asked for permission by calling XController::suspend() before. 
      /// XModel for full featured components
      /// A model that in general can be shared between several view/controller pairs, does not have an explicit owner. 
      /// Every view and also the component that loaded the document may consider itself as an owner. Simply calling XComponent::dispose 
      /// on this model may cause problems, if some members of the "owner community" are currently busy working on the model. 
      /// These problems are handled by explicit closing negotiations through the interface ::com::sun::star::util::XCloseable. 
      /// Direct dispose of the model is allowed only, if this special interface doesn't exist.
      /// </returns>
      public T LoadComponentFromFile<T>(string fileName, string targetFrameName = "_blank", FrameSearchFlag searchFlags = FrameSearchFlag.AUTO, bool hidden = false) where T : Component, new()
      {
         return new T()
         {
            ComObj = LoadComponentFromURLRaw(FileNameToUrl(fileName), targetFrameName, (int)searchFlags, hidden)
         };
      }

      /// <summary>
      /// Loads a component specified by an URL into the specified new or existing frame.
      /// </summary>
      /// <param name="fileName">Specifies the file name of the document to load.</param>
      /// <param name="targetFrameName">
      /// Specifies the name of the frame to view the document in.
      /// If a frame with the specified name already exists, it is used, otherwise it is created. 
      /// There exist some special targets which never can be used as real frame names: 
      /// "_blank" always creates a new frame 
      /// "_default" special UI functionality (e.g. detecting of already loaded documents, using of empty frames of creating of new top frames as fallback) 
      /// "_self", ""(!) means frame himself 
      /// "_parent" address direct parent of frame 
      /// "_top" indicates top frame of current path in tree 
      /// "_beamer" means special sub frame 
      /// </param>
      /// <param name="searchFlags">
      /// Use the values of FrameSearchFlag to specify how to find the specified TargetFrameName.
      /// Note: These flags are optional ones and will be used for non special target names only.
      /// </param>
      /// <param name="arguments">
      /// these arguments specify component or filter specific behavior.
      /// For example, "ReadOnly" with a boolean value specifies whether the document is opened read-only. 
      /// "FilterName" specifies the component type to create and the filter to use, for example: 
      /// "Text - CSV". For more information see ::com::sun::star::document::MediaDescriptor.
      /// </param>
      /// <returns>
      /// Returns a ::com::sun::star::lang::XComponent for successfully loaded documents or NULL if it failed .
      /// This interface is a generic one and can be used to start further requests on loaded document or control the 
      /// lifetime of it (means dispose() it after using). The real document service behind this interface can be one of follow three ones: 
      /// ::com::sun::star::awt::XWindow for simple components Should be used for viewable components only. 
      /// It is not allowed to dispose it after use directly, because the frame containing the component is its owner. 
      /// Because the frame object is not accessible through the interface too, only an interacting user can do this by closing the frames' window. 
      /// XController for richer components Should be used for real editable components which doesn't need a model. 
      /// It is not allowed to dispose it after use directly, because the frame containing the component is its owner. 
      /// Here the object can be disposed by disposing the frame, that the XController::getFrame() method of the controller returns. 
      /// But for visible components the controller should be asked for permission by calling XController::suspend() before. 
      /// XModel for full featured components
      /// A model that in general can be shared between several view/controller pairs, does not have an explicit owner. 
      /// Every view and also the component that loaded the document may consider itself as an owner. Simply calling XComponent::dispose 
      /// on this model may cause problems, if some members of the "owner community" are currently busy working on the model. 
      /// These problems are handled by explicit closing negotiations through the interface ::com::sun::star::util::XCloseable. 
      /// Direct dispose of the model is allowed only, if this special interface doesn't exist.
      /// </returns>
      public T LoadComponentFromFileWithArgs<T>(string fileName, string targetFrameName = "_blank", FrameSearchFlag searchFlags = FrameSearchFlag.AUTO, object[] arguments = null) where T : Component, new()
      {
         if (arguments == null)
         {
            arguments = new object[0];
         }
         return new T()
         {
            ComObj = LoadComponentFromURLRaw(FileNameToUrl(fileName), targetFrameName, (int)searchFlags, arguments)
         };
      }
      #endregion

      #region Utility functions
      
      /// <summary>
      /// Creates anew TextDocument
      /// </summary>
      /// <param name="hidden">true if document should be hidden, false otherwise.</param>
      /// <returns>Returns the new TextDocument.</returns>
      public TextDocument CreateTextDocument(bool hidden = false)
      {
         return LoadComponentFromURL<TextDocument>("private:factory/swriter", hidden: hidden);
      }

      #endregion
   }
}
